{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](https://img-blog.csdnimg.cn/2021041710210731.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2JpdDQ1Mg==,size_16,color_FFFFFF,t_70)\n",
    "\n",
    "![](https://img-blog.csdnimg.cn/20201114105033866.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2JpdDQ1Mg==,size_16,color_FFFFFF,t_70)\n",
    "\n",
    "![](https://img-blog.csdnimg.cn/20201114105210740.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2JpdDQ1Mg==,size_16,color_FFFFFF,t_70)\n",
    "\n",
    "![](https://img-blog.csdnimg.cn/20201114105215682.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2JpdDQ1Mg==,size_16,color_FFFFFF,t_70)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1,   300] loss: 2.205\n",
      "[1,   600] loss: 0.812\n",
      "[1,   900] loss: 0.401\n",
      "accuracy on test set: 89 % \n",
      "[2,   300] loss: 0.315\n",
      "[2,   600] loss: 0.256\n",
      "[2,   900] loss: 0.216\n",
      "accuracy on test set: 94 % \n",
      "[3,   300] loss: 0.180\n",
      "[3,   600] loss: 0.167\n",
      "[3,   900] loss: 0.151\n",
      "accuracy on test set: 95 % \n",
      "[4,   300] loss: 0.131\n",
      "[4,   600] loss: 0.118\n",
      "[4,   900] loss: 0.113\n",
      "accuracy on test set: 96 % \n",
      "[5,   300] loss: 0.090\n",
      "[5,   600] loss: 0.099\n",
      "[5,   900] loss: 0.091\n",
      "accuracy on test set: 96 % \n",
      "[6,   300] loss: 0.072\n",
      "[6,   600] loss: 0.078\n",
      "[6,   900] loss: 0.074\n",
      "accuracy on test set: 97 % \n",
      "[7,   300] loss: 0.060\n",
      "[7,   600] loss: 0.062\n",
      "[7,   900] loss: 0.060\n",
      "accuracy on test set: 97 % \n",
      "[8,   300] loss: 0.049\n",
      "[8,   600] loss: 0.049\n",
      "[8,   900] loss: 0.049\n",
      "accuracy on test set: 97 % \n",
      "[9,   300] loss: 0.037\n",
      "[9,   600] loss: 0.044\n",
      "[9,   900] loss: 0.043\n",
      "accuracy on test set: 97 % \n",
      "[10,   300] loss: 0.032\n",
      "[10,   600] loss: 0.033\n",
      "[10,   900] loss: 0.035\n",
      "accuracy on test set: 97 % \n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "from torchvision import transforms\n",
    "from torchvision import datasets\n",
    "from torch.utils.data import DataLoader\n",
    "import torch.nn.functional as F\n",
    "import torch.optim as optim\n",
    " \n",
    "# prepare dataset\n",
    " \n",
    "batch_size = 64\n",
    "transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))]) # 归一化,均值和方差\n",
    " \n",
    "train_dataset = datasets.MNIST(root='../dataset/mnist/', train=True, download=True, transform=transform)\n",
    "train_loader = DataLoader(train_dataset, shuffle=True, batch_size=batch_size)\n",
    "test_dataset = datasets.MNIST(root='../dataset/mnist/', train=False, download=True, transform=transform)\n",
    "test_loader = DataLoader(test_dataset, shuffle=False, batch_size=batch_size)\n",
    " \n",
    "# design model using class\n",
    " \n",
    " \n",
    "class Net(torch.nn.Module):\n",
    "    def __init__(self):\n",
    "        super(Net, self).__init__()\n",
    "        self.l1 = torch.nn.Linear(784, 512)\n",
    "        self.l2 = torch.nn.Linear(512, 256)\n",
    "        self.l3 = torch.nn.Linear(256, 128)\n",
    "        self.l4 = torch.nn.Linear(128, 64)\n",
    "        self.l5 = torch.nn.Linear(64, 10)\n",
    " \n",
    "    def forward(self, x):\n",
    "        x = x.view(-1, 784).cuda()  # -1其实就是自动获取mini_batch  \n",
    "        x = F.relu(self.l1(x)).cuda()\n",
    "        x = F.relu(self.l2(x)).cuda()\n",
    "        x = F.relu(self.l3(x)).cuda()\n",
    "        x = F.relu(self.l4(x)).cuda()\n",
    "        x = self.l5(x).cuda()\n",
    "        return x  # 最后一层不做激活，不进行非线性变换\n",
    " \n",
    " \n",
    "model = Net()\n",
    "model.cuda()\n",
    "# construct loss and optimizer\n",
    "criterion = torch.nn.CrossEntropyLoss()\n",
    "criterion.cuda()\n",
    "optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)\n",
    " \n",
    "# training cycle forward, backward, update\n",
    " \n",
    " \n",
    "def train(epoch):\n",
    "    running_loss = 0.0\n",
    "    for batch_idx, data in enumerate(train_loader, 0):\n",
    "        # 获得一个批次的数据和标签\n",
    "        inputs, target = data\n",
    "        inputs = inputs.cuda()\n",
    "        target = target.cuda()\n",
    "        optimizer.zero_grad()\n",
    "        # 获得模型预测结果(64, 10)\n",
    "        outputs = model(inputs)\n",
    "        # 交叉熵代价函数outputs(64,10),target（64）\n",
    "        loss = criterion(outputs, target)\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    " \n",
    "        running_loss += loss.item()\n",
    "        if batch_idx % 300 == 299:\n",
    "            print('[%d, %5d] loss: %.3f' % (epoch+1, batch_idx+1, running_loss/300))\n",
    "            running_loss = 0.0\n",
    " \n",
    " \n",
    "def test():\n",
    "    correct = 0\n",
    "    total = 0\n",
    "    with torch.no_grad():\n",
    "        for data in test_loader:\n",
    "            images, labels = data\n",
    "            images = images.cuda()\n",
    "            labels = labels.cuda()\n",
    "            outputs = model(images)\n",
    "            _, predicted = torch.max(outputs.data, dim=1) # dim = 1 列是第0个维度，行是第1个维度\n",
    "            # print(\"predicted = \",predicted,\"\\tlabel = \",labels)\n",
    "            total += labels.size(0)\n",
    "            correct += (predicted == labels).sum().item() # 张量之间的比较运算\n",
    "    print('accuracy on test set: %d %% ' % (100*correct/total))\n",
    " \n",
    " \n",
    "if __name__ == '__main__':\n",
    "    for epoch in range(10):\n",
    "        train(epoch)\n",
    "        test()"
   ]
  }
 ],
 "metadata": {
  "interpreter": {
   "hash": "44143c5ac5f3ceb8e37c69c3af73325ae55d21292b2c7b54871fd886482dde4c"
  },
  "kernelspec": {
   "display_name": "Python 3.6.13 ('pytorch')",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.13"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
